#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include "osal.h"

#include "hdf_log.h"
#include "hdf_base.h"
#include "hdf_device_desc.h"
#include "device_resource_if.h"

#include "sht3x.h"
#include "sht3x_drv.h"

// 日志标记
#define HDF_LOG_TAG     sht3x

static int32_t sht3xDriverBind(struct HdfDeviceObject *deviceObject);
static int32_t sht3xDriverInit(struct HdfDeviceObject *deviceObject);
static void sht3xDriverRelease(struct HdfDeviceObject *deviceObject);

// 处理用户态下发的数据
static int32_t sht3xDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    int ret = HDF_SUCCESS;
    sht3x_data Data = {0};
    uint8_t mode;
    int64_t samplingInterval;
    float tempData, humiData;
    DevHandle sht3xDev = NULL;

    // 参数检查
    if (client == NULL || client->device == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }

    // 获取设备节点
    sht3xDev = (DevHandle)client->device->priv;
    if (sht3xDev == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }

    // 命令处理
    switch(cmdCode) {
        case SHT3X_CMD_SET_MODE:// 设置模块工作模式
            if (!HdfSbufReadUint8(data, &mode)) {
                HDF_LOGE("sbuf read fail.");
                return HDF_FAILURE;
            }
            ret = sht3xDrvSetMode(sht3xDev, mode);
            break;
        case SHT3X_CMD_GET_TEMP_HUMI:
            ret = sht3xDrvGetTemperature(sht3xDev, &(Data.temperature));// 温度数据
            ret |= sht3xDrvGetHumidity(sht3xDev, &(Data.humidity));// 湿度数据
            if (ret == 0 && reply != NULL) {
                if (!HdfSbufWriteBuffer(reply, (void *)&Data, sizeof(sht3x_data))) {
                    HDF_LOGE("sbuf write fail.");
                    return HDF_FAILURE;
                }
            }
            break;
        case SHT3X_CMD_ENABLE:// 使能
            ret = sht3xDrvEnable(sht3xDev);
            break;
        case SHT3X_CMD_DISABLE:// 失能
            ret = sht3xDrvDisable(sht3xDev);
            break;
        case SHT3X_CMD_SET_SAMPLING_INTERVAL:
            if (!HdfSbufReadInt64(data, &samplingInterval)) {
                HDF_LOGE("sbuf read fail.");
                return HDF_FAILURE;
            }
            ret = sht3xDrvSetSamplingInterval(sht3xDev, samplingInterval);
            break;
        case SHT3X_CMD_SOFT_RESET:
            ret = sht3xDrvSoftReset(sht3xDev);
            break;
        case SHT3X_CMD_GET_TEMP:
            ret = sht3xDrvGetTemperature(sht3xDev, &tempData);
            if (ret == 0 && reply != NULL) {
                if (!HdfSbufWriteBuffer(reply, (void *)&tempData, sizeof(float))) {
                    HDF_LOGE("sbuf write fail.");
                    return HDF_FAILURE;
                }
            }
            break;
        case SHT3X_CMD_GET_HUMI:
            ret = sht3xDrvGetHumidity(sht3xDev, &humiData);
            if (ret == 0 && reply != NULL) {
                if (!HdfSbufWriteBuffer(reply, (void *)&humiData, sizeof(float))) {
                    HDF_LOGE("sbuf write fail.");
                    return HDF_FAILURE;
                }
            }
            break;
        default:
            HDF_LOGE("cmd unsupport.");
            return HDF_ERR_NOT_SUPPORT;
    }

    return HDF_SUCCESS;
}

// 读取配置
static int32_t _sht3xAttachDeviceResource(
    sht3xDrvCfg *sht3xCfg, const struct DeviceResourceNode *resourceNode)
{
    int32_t ret = HDF_SUCCESS;
    uint16_t port_num = 0;// 使用的I2C端口
    uint32_t addr = 0;

    // 获取解析操作接口
    struct DeviceResourceIface *dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (dri == NULL 
        || dri->GetUint32 == NULL 
        || dri->GetUint16 == NULL
    ) 
    {
        HDF_LOGE("DeviceResourceIface is invalid.");
        ret = HDF_FAILURE;
        goto _sht3xAttachDeviceResourceExit;
    }

    // 读取sht3x使用的i2c端口号
    if (dri->GetUint16(resourceNode, "port", &port_num, 0) != HDF_SUCCESS) {
        HDF_LOGE("sht3x config, read port_num fail.");
        ret = HDF_FAILURE;
        goto _sht3xAttachDeviceResourceExit;
    }

    // 读取sht3x ADDR pin引脚的电平
    if (dri->GetUint32(resourceNode, "addr", &addr, 0) != HDF_SUCCESS) {
        HDF_LOGE("sht3x config, read addr fail,use default slave addr.");
        addr = 0;
    }

    // 参数设置
    sht3xCfg->i2cPortNum = port_num;
    sht3xCfg->adVal = addr;

_sht3xAttachDeviceResourceExit:
    return ret;
}

// 释放驱动相关资源
static void sht3xDriverRelease(struct HdfDeviceObject *deviceObject)
{
    DevHandle sht3xDev = NULL;

    printf("sht3xDriverRelease.");

    // 设备节点
    sht3xDev = (DevHandle)deviceObject->priv;

    // 如果设备节点非空,需要释放相关资源
    if (sht3xDev != NULL) {
        sht3xDrvClose(sht3xDev);
    }

    deviceObject->priv = NULL;
}

// 驱动匹配接口
static int32_t sht3xDriverBind(struct HdfDeviceObject *deviceObject)
{
    printf("sht3xDriverBind.");

    // 参数检查
    if (deviceObject == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }

    // 初始化驱动的服务接口
    static struct IDeviceIoService sht3xService = {
        .Dispatch = sht3xDriverDispatch,
    };

    // 注册驱动驱动服务
    deviceObject->service = (struct IDeviceIoService *)&sht3xService;
    return HDF_SUCCESS;
}

// 驱动初始化
static int32_t sht3xDriverInit(struct HdfDeviceObject *deviceObject)
{
    int32_t ret = HDF_SUCCESS;
    DevHandle sht3xDev = NULL;
    sht3xDrvCfg sht3xCfg = {0};

    HDF_LOGE("sht3xDriverInit.");

    // 参数检查
    if (deviceObject == NULL) {
        HDF_LOGE("ptr is null!");
        ret = HDF_ERR_INVALID_OBJECT;
        goto sht3xDriverInitFail;
    }

    // 获取 hcs 配置
    ret = _sht3xAttachDeviceResource(&sht3xCfg, deviceObject->property);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("_sht3xAttachDeviceResource fail, ret : %#x.\r\n", ret);
        ret = HDF_FAILURE;
        goto sht3xDriverInitFail;
    }

    // 打开sht3x设备
    sht3xDev = sht3xDrvOpen(&sht3xCfg);
    if (sht3xDev == NULL) {
        HDF_LOGE("sht3xDrvOpen fail.");
        ret = HDF_FAILURE;
        goto sht3xDriverInitFail;
    }

    // 初始化成功后进行一次复位
    sht3xDrvSoftReset(sht3xDev);

    // 配置节点私有属性
    deviceObject->priv = (void *)sht3xDev;
    return HDF_SUCCESS;

sht3xDriverInitFail:

    // 出错返回
    if (sht3xDev) {
        sht3xDrvClose(sht3xDev);
    }

    return ret;
}

// 驱动句柄
struct HdfDriverEntry g_sht3xDriverEntry = {
    .moduleVersion = 1,                 // 版本
    .moduleName = "sht3x",              // 驱动名
    .Bind = sht3xDriverBind,            // 驱动入口函数
    .Init = sht3xDriverInit,            // 驱动初始化函数
    .Release = sht3xDriverRelease,      // 驱动释放函数
};

// 注册驱动
HDF_INIT(g_sht3xDriverEntry);